/* 
 * File:   ROI.cpp
 * Author: Guilherme Monteiro
 */

#include <vector>

#include "../headers/ROI.h"

/**
 * Constructor of ROI.
 * 
 * @param leftUpper
 * @param rightBottom
 * @param originalHighResolutionImagePath: path to original high page image that will be used to heuristic
 * @param originalLowResolutionImagePath: path to original low page image that will be used to heuristic
 * @param highResolutionImageCutIncompletePath: 
 * @param lowResolutionImageCutIncompletePath: path to low
 * @param logImageIncompletePath: path to log image without <index>.png
 * @param indexROI: index of roi (table) in the page
 */
ROI::ROI(CvPoint leftUpper, CvPoint rightBottom, 
        string originalHighResolutionImagePath, 
        string originalLowResolutionImagePath,
        string lowResolutionImageCutIncompletePath,
        string highResolutionImageCutIncompletePath,
        string modelPreviewIncompletePath,
        string logImageIncompletePath, 
        bool isRotated, int indexROI) {
    
    setOriginalHighResolutionImagePath(originalHighResolutionImagePath);
    setOriginalLowResolutionImagePath(originalLowResolutionImagePath);
    
    setIndexROI(indexROI);
    
    setLowResolutionImageCutPath(lowResolutionImageCutIncompletePath);
    setHighResolutionImageCutPath(highResolutionImageCutIncompletePath);
    setModelPreviewPath(modelPreviewIncompletePath);
    setLogImagePath(logImageIncompletePath, isRotated);
    
    setLeftUpper(leftUpper);
    setRightBottom(rightBottom);
    
    setImageROI();
}

ROI::ROI(const ROI& orig) {
}

ROI::~ROI() {
}

/**
 * Configure the left upper point.
 * 
 * @param point
 */
void ROI::setLeftUpper(CvPoint point) throw (NullImageException) {
    IplImage* originalHighImage = cvLoadImage(getOriginalHighResolutionImagePath().c_str());
    
    if(originalHighImage == 0) {
        throw NullImageException(getOriginalHighResolutionImagePath());
    }
    
    if(point.x > originalHighImage->width) {
        point.x = originalHighImage->width;
    }
    
    if(point.y > originalHighImage->height) {
        point.y = originalHighImage->height;
    }
    
    cvReleaseImage(&originalHighImage);
    
    this->leftUpper = point;
}

/**
 * Returns the left upper point.
 * 
 * @return leftUpper
 */
CvPoint ROI::getLeftUpper() {
    return this->leftUpper;
}

/**
 * Configure the right bottom point.
 * Is set a care border (+10) in the cut to
 * better the visualization and don't cut the
 * line borders of the image. If the band care
 * cross the page limits, the point is adapted
 * to keep in the page border.
 * 
 * @param point
 */
void ROI::setRightBottom(CvPoint point) throw (NullImageException) {
    int CARE_BORDER_SIZE = 3;
    IplImage* originalHighImage = cvLoadImage(getOriginalHighResolutionImagePath().c_str());

    if(originalHighImage == 0) {
        throw NullImageException(getOriginalHighResolutionImagePath());
    }
    
    if(point.x + CARE_BORDER_SIZE > originalHighImage->width) {
        point.x = originalHighImage->width;
    }
    else {
        point.x += CARE_BORDER_SIZE;
    }
    
    if(point.y + CARE_BORDER_SIZE > originalHighImage->height) {
        point.y = originalHighImage->height;
    }
    else {
        point.y += CARE_BORDER_SIZE;
    }
    
    cvReleaseImage(&originalHighImage);
    this->rightBottom = point;
}

/**
 * Return right bottom point.
 * 
 * @return rightBottom
 */
CvPoint ROI::getRightBottom() {
    return this->rightBottom;
}

/**
 * Configure the ROI. Here the highResolutionImage is cut.
 * 
 * @see VectorROICreator
 */
void ROI::setImageROI() throw (NullImageException) { 
    
    IplImage* img = cvLoadImage(getOriginalHighResolutionImagePath().c_str());

    if(img == 0) {
        throw NullImageException(getOriginalHighResolutionImagePath());
    }
    
    IplImage* imageCut;
    try {
        ImageCutter* cutter = new ImageCutter(img, leftUpper, rightBottom);
        imageCut = cutter->cut();
    }
    catch(InvalidRectException &ire) {
        cout << "Your entry to this table is invalid. To be valid it need be a rectangle. The program will be closed." << endl;
        exit(1);
    }
    
    this->imageROI = cvCreateImage(cvGetSize(imageCut), IPL_DEPTH_8U, 3);
    this->imageROI = cvCloneImage(imageCut);
    
//    cvShowImage("image roi in ROI", this->imageROI);
//    cvNamedWindow("image roi in ROI", CV_WINDOW_FREERATIO);
//    cvWaitKey(0);
//    cvDestroyWindow("image roi in ROI");
    cvReleaseImage(&imageCut);
}

/**
 * Configures the image roi to give image.
 * 
 * @param r: new roi
 */
void ROI::setImageROI(IplImage* r) {
    this->imageROI = r;
}

/**
 * Returns the micro image that agree to roi
 * in original image. The ROI is created in VectorROICreator
 * 
 * @return imageROI
 * 
 * @see VectorROICreator
 */
IplImage* ROI::getImageROI() {
    return this->imageROI;
}

/**
 * Configures the original high resolution image
 * path: the path to page of the book.
 * 
 * @param path
 */
void ROI::setOriginalHighResolutionImagePath(string path) {
    this->originalHighResolutionImagePath = path;
}

/**
 * Returns the original high resolution image path.
 * 
 * @return originalHighResolutionImagePath
 */
string ROI::getOriginalHighResolutionImagePath() {
    return this->originalHighResolutionImagePath;
}

/**
 * Configures the original low resolution image
 * path.
 * 
 * @param originalLowResolutionImagePath
 */
void ROI::setOriginalLowResolutionImagePath(string originalLowResolutionImagePath) {
    this->originalLowResolutionImagePath = originalLowResolutionImagePath;
}

/**
 * Returns the original low
 * resolution image path.
 * 
 * @return originalLowResolutionImagePath
 */
string ROI::getOriginalLowResolutionImagePath() {
    return this->originalLowResolutionImagePath;
}

/**
 * Return the model preview path with
 * index roi added to it.
 * 
 * @return model preview complete path
 */
string ROI::getModelPreviewPath() {
    return this->modelPreviewPath;
}

/**
 * Configures the model preview path, put the index
 * roi on it.
 * 
 * @param modelPreviewIncompletePath: model preview path without roi index neither .png
 */
void ROI::setModelPreviewPath(string modelPreviewIncompletePath) {
    stringstream index;
    index << this->getIndexROI();
    this->modelPreviewPath = modelPreviewIncompletePath + "_" + index.str() + ".png";
//    printf("modelPreviewPath: %s\n", this->modelPreviewPath.c_str());
}

/**
 * Configures the complete path
 * to low resolution image cut to the
 * roi (region of interest).
 * 
 * @param lowResolutionImageCutIncompletePath
 */
void ROI::setLowResolutionImageCutPath(string lowResolutionImageCutIncompletePath) {
    stringstream index;
    index << this->getIndexROI();
    this->lowResolutionImageCutPath = lowResolutionImageCutIncompletePath + "_" + index.str() + ".png";
}


/**
 * Returns the low resolution image
 * cut path, here the image is the roi.
 * 
 * @return lowResolutionImageCutPath
 */
string ROI::getLowResolutionImageCutPath() {
    return this->lowResolutionImageCutPath;
}

/**
 * Configures the complete path
 * to high resolution image, here
 * the image is the roi.
 * 
 * @param highResolutionImageCutIncompletePath
 */
void ROI::setHighResolutionImageCutPath(string highResolutionImageCutIncompletePath) {
    stringstream index;
    index << this->getIndexROI();
    this->highResolutionImageCutPath = highResolutionImageCutIncompletePath + "_" + index.str() + ".png";
}


/**
 * Returns the high resolution image
 * cut (roi) path.
 * 
 * @return highResolutionImageCutPath
 */
string ROI::getHighResolutionImageCutPath() {
    return this->highResolutionImageCutPath;
}

/**
 * Configures the index roi. The index
 * serves to identify the roi in the image
 * of page.
 * 
 * @param index
 */
void ROI::setIndexROI(int index) {
    this->indexROI = index;
}

/**
 * Returns the index of roi.
 * 
 * @return index
 */
int ROI::getIndexROI() {
    return this->indexROI;
}

/**
 * Configures the log image path.
 * 
 * @param logImageIncompletePath
 * @param isRotated
 */
void ROI::setLogImagePath(string logImageIncompletePath, bool isRotated) {
    stringstream index;
    index << this->getIndexROI();
    if(!isRotated) {
        this->logImagePath = logImageIncompletePath + "_" + index.str() + ".png"; 
        //this->logImagePath = logImageIncompletePath + "_" + index.str() + "_5" + ".png"; // ==> to experience
        //printf("logImagePath: %s\n", logImagePath.c_str());
    }
    else {
        this->logImagePath = logImageIncompletePath + "_r_" + index.str() + ".png"; 
        //this->logImagePath = logImageIncompletePath + "_" + index.str() + "_5" + ".png"; // ==> to experience
        //printf("logImagePath: %s\n", logImagePath.c_str());
    }
}

/**
 * Returns the log image path.
 * 
 * @return log image path
 */
string ROI::getLogImagePath() {
    return this->logImagePath;
}

/**
 * Returns the up line of the table.
 * 
 * @return up line table
 */
Line ROI::getUpLineTable() {
    return Line(cvPoint(0, 0), 
            cvPoint(getRightBottom().x - getLeftUpper().x, 0)); // up line
}

/**
 * Returns the left line of the table.
 * 
 * @return left line table
 */
Line ROI::getLeftLineTable() {
    return Line(cvPoint(0, 0), 
            cvPoint(0, getRightBottom().y-getLeftUpper().y)); // left line
}

/**
 * Returns the right line of the table.
 * 
 * @return right line table
 */
Line ROI::getRightLineTable() {
    return Line(cvPoint(getRightBottom().x - getLeftUpper().x, 0),
            cvPoint(getRightBottom().x - getLeftUpper().x, getRightBottom().y - getLeftUpper().y)); // right line
}

/**
 * Returns the down line of the table.
 * 
 * @return down line table
 */
Line ROI::getDownLineTable() {
    return Line(cvPoint(0, getRightBottom().y - getLeftUpper().y), 
            cvPoint(getRightBottom().x - getLeftUpper().x, getRightBottom().y - getLeftUpper().y)); // down line
}

/**
 * Makes a relese of the imageROI.
 */
void ROI::releaseROI() {
    cvReleaseImage(&this->imageROI);
}
